package com.insight.modules.quartz.job;

import com.alibaba.fastjson.JSONObject;
import com.yuanqiao.insight.modules.equipment.entity.EquipmentPlanExecution;
import com.yuanqiao.insight.modules.equipment.service.IEquipmentPlanExecutionService;
import com.yuanqiao.insight.modules.flowable.constant.FlowableConstant;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import com.insight.common.system.api.ISysBaseAPI;
import com.insight.common.system.vo.LoginUser;
import com.insight.common.util.FillRuleUtil;
import com.insight.common.util.SpringContextUtils;
import org.jetbrains.annotations.NotNull;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 设备执行计划任务类，实现Quartz的Job接口
 * 负责启动设备执行流程，创建业务数据并关联流程实例
 */
@Slf4j
@Data
public class EquipmentJob implements Job {

    /**
     * 任务执行入口方法，Quartz调度时调用
     *
     * @param jobExecutionContext 作业执行上下文，包含任务参数等信息
     * @throws JobExecutionException 任务执行异常抛出
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取任务参数Map
        Map<String, Object> variables = jobExecutionContext.getMergedJobDataMap().getWrappedMap();

        // 通过Spring容器获取Flowable相关服务bean
        RepositoryService repositoryService = SpringContextUtils.getBean(RepositoryService.class);
        ISysBaseAPI iSysBaseAPI = SpringContextUtils.getBean(ISysBaseAPI.class);
        RuntimeService runtimeService = SpringContextUtils.getBean(RuntimeService.class);

        // 处理人用户名
        String dealUser = (String) variables.get("dealUser");
        // 审核人用户名
        String checkUser = (String) variables.get("checkUser");
        // 分类
        String category = (String) variables.get("category");
        // 设备计划ID
        String equipmentPlanId = (String) variables.get("equipmentPlanId");
        // 设备ID列表
        List<String> equipmentIdList = (List) variables.get("equipmentIdList");
        // 设计配置信息
        JSONObject designConfig = (JSONObject) variables.get("designConfig");

        // 查询流程定义，获取最新版本的设备流程定义信息
        ProcessDefinition processDefinition = repositoryService
                .createProcessDefinitionQuery()
                .processDefinitionKey("equipment")
                .latestVersion()
                .singleResult();

        // 根据处理人用户名查询用户信息
        LoginUser userById = iSysBaseAPI.getUserByName(dealUser);

        // 设置业务标题，格式：【用户名】流程名称
        variables.put(FlowableConstant.BUSINESS_TITLE, "【" + userById.getRealname() + "】" + processDefinition.getName());

        // 设置流程发起人ID，Flowable流程身份认证
        Authentication.setAuthenticatedUserId(dealUser);

        // 遍历设备列表，为每个设备启动一个流程实例并创建业务数据
        for (String equipmentId : equipmentIdList) {
            // 启动流程实例
            ProcessInstance processInstance = startProcess(variables, runtimeService, processDefinition, userById, equipmentId);

            // 创建对应业务数据（设备计划执行记录）
            EquipmentPlanExecution equipmentPlanExecution = createBiz(dealUser, checkUser, category, equipmentId, processInstance, equipmentPlanId, designConfig);

            // 关联流程变量，便于监听器使用执行计划ID
            addVariableLink(runtimeService, processInstance, equipmentPlanExecution);
        }
    }

    /**
     * 给流程实例设置业务执行计划ID变量，供流程监听器调用
     *
     * @param runtimeService      流程运行服务
     * @param processInstance     当前流程实例
     * @param equipmentPlanExecution 设备计划执行实体
     */
    private void addVariableLink(RuntimeService runtimeService, ProcessInstance processInstance, EquipmentPlanExecution equipmentPlanExecution) {
        // 监听器相关类：
        // com.insight.modules.system.listener.EquipmentDealListener
        // com.insight.modules.system.listener.EquipmentCheckListener
        runtimeService.setVariable(processInstance.getId(), "equipmentPlanExecutionId", equipmentPlanExecution.getId());
    }

    /**
     * 创建业务表数据（设备计划执行实体），并保存数据库
     *
     * @param dealUser         处理人用户名
     * @param checkUser        审核人用户名
     * @param category         设备计划分类
     * @param equipmentId      设备ID
     * @param processInstance  流程实例
     * @param equipmentPlanId  设备计划ID
     * @param designConfig     设计配置信息
     * @return 创建的设备计划执行实体对象
     */
    @NotNull
    private EquipmentPlanExecution createBiz(String dealUser, String checkUser, String category, String equipmentId, ProcessInstance processInstance, String equipmentPlanId, JSONObject designConfig) {
        // 从Spring容器中获取设备计划执行服务接口
        IEquipmentPlanExecutionService iEquipmentPlanExecutionService = SpringContextUtils.getBean(IEquipmentPlanExecutionService.class);

        EquipmentPlanExecution equipmentPlanExecution = new EquipmentPlanExecution();

        // 设置流程实例ID
        equipmentPlanExecution.setActId(processInstance.getId());
        // 设置设备计划ID
        equipmentPlanExecution.setEquipmentPlanId(equipmentPlanId);
        // 设置设备ID
        equipmentPlanExecution.setEquipmentId(equipmentId);
        // 设置执行人签名（用户名）
        equipmentPlanExecution.setExecutorSignature(dealUser);
        // 设置审核人签名（用户名）
        equipmentPlanExecution.setScrutatorSignature(checkUser);
        // 设置设备计划分类
        equipmentPlanExecution.setCategory(category);
        // 设置状态为未完成
        equipmentPlanExecution.setState("unfinished");
        // 设置创建时间为当前时间
        equipmentPlanExecution.setCreateTime(new Date());
        // 设置设计配置信息
        equipmentPlanExecution.setDesignConfig(designConfig);

        // 生成业务编码所需的参数
        JSONObject formData = new JSONObject();
        formData.put("code-generation-bind", category);

        // 通过编码规则工具生成流水号
        String codeGeneration = (String) FillRuleUtil.executeRule("biz_code_generation", formData);
        if (StringUtils.isEmpty(codeGeneration)) {
            throw new IllegalArgumentException("编码生成失败：规则执行异常");
        }
        // 设置流水号编码
        equipmentPlanExecution.setSerialNumber(codeGeneration);

        // 保存业务实体
        iEquipmentPlanExecutionService.save(equipmentPlanExecution);

        return equipmentPlanExecution;
    }

    /**
     * 启动流程实例
     *
     * @param variables         流程变量
     * @param runtimeService    流程运行服务
     * @param processDefinition 流程定义
     * @param userById          处理人用户实体
     * @param equipmentId       设备ID
     * @return 流程实例对象
     */
    private ProcessInstance startProcess(Map<String, Object> variables, RuntimeService runtimeService, ProcessDefinition processDefinition, LoginUser userById, String equipmentId) {
        // 设置设备ID变量
        variables.put("equipmentId", equipmentId);

        // 创建流程实例构建器，设置流程定义ID、实例名称和变量，启动流程
        ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
                .processDefinitionId(processDefinition.getId())
                .name(String.format("【%s】%s", userById.getRealname(), processDefinition.getName()))
                .variables(variables)
                .start();

        return processInstance;
    }
}
